package srvbiz

import (
	"cloud_worm/access/server/client"
	"cloud_worm/util/proto/ujson"
	"github.com/golang/glog"
	"cloud_worm/util/umodels/mysqldb/dbmanager"
	"cloud_worm/util/uid"
	"cloud_worm/access/config"
	"time"
	"fmt"
	"os"
)

type MsgWormId struct {
}

func (w *MsgWormId) Deal(agent *client.Agent, data []byte) {
	var msg ujson.MsgId
	if err := msg.UnmarshalJSON(data); err != nil {
		glog.Errorf("worm'%s' id msg Unmarshal failed: %s", agent.IP, err.Error())
		return
	}

	if err := w.handleWormId(agent, &msg); err != nil {
		glog.Errorf("deal worm id error: %s", err.Error())

		client.AgentPoolInst.DelAgent(agent)
		return
	}

	return
}

func (w *MsgWormId) handleWormId(agent *client.Agent, msg *ujson.MsgId) error {
	response := new(ujson.MsgId)
	var err error

	if msg.HaveId == false {
		// 没有 worm id，创建一个 worm id
		err = w.newWormId(agent, response)
	} else {
		wormId := &dbmanager.WormId{
			AgentId: msg.Id,
		}
		err1 := wormId.Read("agent_id")
		if err1 != nil {
			// 没有查到该 worm id的记录，创建一个新的 worm id
			err = w.newWormId(agent, response)
		} else {
			// 存在该 worm id记录，则判断该 worm id是否已经有在线的
			if client.AgentPoolInst.HaveConnByID(wormId.AgentId) {
				// 在线，说明该wolverine id已经在用；为新接入的分配新的wolverine id
				err = w.newWormId(agent, response)
			} else {
				// 不在线，说明是掉线然后重新连接
				response.Id = wormId.AgentId
				response.HaveId = true
				response.IsCreate = false
			}
		}
	}

	content, err2 := response.MarshalJSON()
	if err2 != nil {
		return fmt.Errorf("response msg id Marshal error: %s", err2.Error())
	}
	sendMsg := ujson.ProtoMsg{
		Type: ujson.ProtoId,
		Content: content,
	}
	buf, err2 := sendMsg.MarshalJSON()
	if err2 != nil {
		return fmt.Errorf("send msg id Marshal error: %s", err2.Error())
	}
	if errWrite := agent.Connection.Write(buf); errWrite != nil {
		return fmt.Errorf("send msg id back for '%s' error: %s", agent.IP, errWrite.Error())
	}

	if err == nil {
		agent.Id = response.Id
		agent.Pid = os.Getpid()
		client.AgentPoolInst.AddAgent(agent)
	}

	return nil
}

func (w *MsgWormId) newWormId(agent *client.Agent, resp *ujson.MsgId) error {
	wormId := dbmanager.WormId{}
	maxId, err := wormId.SelectMaxId()
	if err != nil {
		resp.HaveId = false
		resp.Id = ""
		return err
	}

	/**
     本身利用auto increase的id作为入参，但是为了防止并发时出现同一个id，导致insert mysql失败，所以加入纳秒timestamp
     time.Now().UnixNano()
     */
	idFactory := uid.AgentId{
		Idc: config.ConfInst.Server.IdcNumber,
		Sequence: maxId + 1,
		NanoTimeStamp: time.Now().UnixNano(),
	}
	id := idFactory.Sha1()

	// 将id写入到db中
	wormId.AgentId = id
	wormId.IP = agent.IP
	wormId.Created = time.Now().Unix()
	wormId.Updated = wormId.Created
	if err := wormId.Insert(); err != nil {
		resp.HaveId = false
		resp.Id = ""
		return err
	}

	resp.Id = id
	resp.HaveId = true
	resp.IsCreate = true
	glog.Infof("create new id for '%s': %s", agent.IP, id)

	return nil
}